﻿using MiniFox.Components;
using RazorEngineCore;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TemplateEngine.Events;
using TemplateEngine.Models;
using TemplateEngine.Providers;

namespace TemplateEngine
{
    /// <summary>
    /// 
    /// </summary>
    public abstract class TemplateServiceBase : ITemplateService
    {
        Encoding _encoding;
        /// <summary>
        /// 
        /// </summary>
        public event EventHandler<ResovlingEventArgs> Resovling;
        /// <summary>
        /// 
        /// </summary>
        public event EventHandler<ResovledEventArgs> Resovled;

        /// <summary>
        /// 
        /// </summary>
        protected TemplateServiceBase() : this(Encoding.UTF8)
        {

        }
        /// <summary>
        /// 
        /// </summary>
        protected TemplateServiceBase(Encoding encoding)
        {
            _encoding = encoding;
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual Encoding TemplateEncoding
        {
            get { return _encoding; }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="templateContent"></param>
        /// <returns></returns>
        public abstract string Resolve(object model, string templateContent);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="templateContent"></param>
        /// <returns></returns>
        public abstract Task<string> ResolveAsync(object model, string templateContent);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        protected abstract TemplateDo GetTemplate(string name);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        protected abstract Task<TemplateDo> GetTemplateAsync(string name);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        protected virtual object Prepare(object model)
        {
            return model;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        public virtual string Resolve(string name, object model)
        {
            TemplateDo templateDo = this.GetTemplate(name);
            string templateContent = templateDo.Content;
            model = this.Prepare(model);
            this.OnResolving(model, templateContent);
            string result = Resolve(model, templateContent);
            this.OnResovled(model, templateContent, result);
            return result;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        public virtual async Task<string> ResolveAsync(string name, object model)
        {
            TemplateDo templateDo = await this.GetTemplateAsync(name);
            string templateContent = templateDo.Content;
            model = this.Prepare(model);
            this.OnResolving(model, templateContent);
            string result = await ResolveAsync(model, templateContent);
            this.OnResovled(model, templateContent, result);
            return result;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="templateContent"></param>
        protected virtual void OnResolving(object model, string templateContent)
        {
            this.Resovling?.Invoke(this, new ResovlingEventArgs
            {
                Model = model,
                Template = templateContent
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="templateContent"></param>
        /// <param name="result"></param>
        protected virtual void OnResovled(object model, string templateContent, string result)
        {
            this.Resovled?.Invoke(this, new ResovledEventArgs
            {
                Model = model,
                Template = templateContent,
                Result = result
            });
        }
    }
}
